#!/usr/bin/python
# -----------------------------------------------------------------------------
# Copyright (c) 2011, MIPS Technologies, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright
#     notice, this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of MIPS Technologies, Inc. nor the
#     names of its contributors may be used to endorse or promote products
#     derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES, LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------

import ConfigParser
import Host
import optparse
import os
import re
import sys
import Utils
import tempfile
import subprocess

class Config(object):
    (MODE_GCC, MODE_GXX) = (1, 2)

    def __init__(self, mode):
        self.mode = mode
        self.cfg = ConfigParser.ConfigParser()

    def read(self):
        cpath = _get_cfg_path()

        if not os.path.isfile(cpath):
            _write_config(cpath)

        self.cfg.read([cpath])

    def get_clang_loc(self):
        return self.cfg.get(self._get_section(), 'clang_loc')

    def get_clangxx_loc(self):
        return self.cfg.get(self._get_section(), 'clangxx_loc')

    def get_llvm_loc(self):
        return self.cfg.get('general', 'llvm_loc')

    def get_asm_loc(self):
        return self.cfg.get(self._get_section(), 'asm_loc')

    def get_ld_loc(self):
        return self.cfg.get(self._get_section(), 'ld_loc')

    def get_includes(self, iscxx, tgtstr):
        incs = self.cfg.items('includes')
        for (key, val) in incs:
          if re.search(tgtstr.lower(), key):
            if iscxx or val.find("c++") < 0:
              yield val

    def _get_section(self):
        values = {
            Config.MODE_GCC: 'gcc',
            Config.MODE_GXX: 'g++',
        }
        return values.get(self.mode)

def _get_cfg_path():
    return os.path.join(os.path.dirname(__file__), 'driver.cfg')

def getIncDirs(gxxloc):
  targets = [ ["mips32", "EL", "32"],  ["mips32", "EB", "32"],
              ["mips64", "EL", "64"],  ["mips64", "EB", "64"], 
              ["mips16", "EL", "32"],  ["mips16", "EB", "32"] ]
  
  print gxxloc

  dirs = ""
  StartStr = "#include <...> search starts here:"
  EndStr = "End of search list."

  for t in targets:
    f = tempfile.NamedTemporaryFile(suffix=".cpp")
    comm = gxxloc + " -" + t[0] + " -" + t[1] + " -mabi=" + t[2] + " -v -S " + f.name + " -o /dev/null"
    p = subprocess.Popen(comm, shell=True, stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    stdout = []

    adddirs = False
    tgtstr = "inc-" + t[0] + "-" + t[1] + "-" + t[2] + "-"
    cnt = 0

    while True:
        line = p.stdout.readline()
        if line.find(StartStr) >= 0:
          adddirs = True
        elif line.find(EndStr) >= 0:
          adddirs = False
        elif adddirs:
          dirs += tgtstr + str(cnt) + "=" + line.strip() + "\n"
          cnt += 1
        #stdout.append(line)
        #print line,
        if line == '' and p.poll() != None:
            break
  return dirs
    #print ''.join(stdout)

def _write_config(cfg_path, llvm_root=None, gcc_root=None):
    host = Host.Host()

    if llvm_root is not None:
        llvm_loc    = os.path.join(llvm_root, "bin/llc")
        clang_loc   = os.path.join(llvm_root, "bin/clang")
        clangxx_loc = os.path.join(llvm_root, "bin/clang++")
    else:
      llvm_loc    = host.get_llc_path()
      clang_loc   = host.get_clang_path()
      clangxx_loc = host.get_clangxx_path()

    if gcc_root is not None:
        gcc_loc = os.path.join(gcc_root, "bin/mips-linux-gnu-gcc")
        gxx_loc = os.path.join(gcc_root, "bin/mips-linux-gnu-g++")
    else:
      gcc_loc     = host.get_mips_gcc_path()
      gxx_loc     = host.get_mips_gxx_path()

    if gcc_root is None:
        gcc_root = os.path.dirname(host.get_toolchain_dir_path())

    gcc_ver = Utils.get_gcc_ver(gcc_loc)

    f = open(cfg_path, 'w') 
    try:
        f.write('[general]\n')
        f.write('llvm_loc = %s\n' % llvm_loc)
        f.write('\n')
        f.write('[gcc]\n')
        f.write('clang_loc = %s\n' % clang_loc)
        f.write('clangxx_loc = %s\n' % clangxx_loc)
        f.write('asm_loc = %s\n' % gcc_loc)
        f.write('ld_loc = %s\n' % gcc_loc)
        f.write('\n')
        f.write('[g++]\n')
        f.write('clang_loc = %s\n' % clangxx_loc)
        f.write('clangxx_loc = %s\n' % clangxx_loc)
        f.write('asm_loc = %s\n' % gxx_loc)
        f.write('ld_loc = %s\n' % gxx_loc)
        f.write('\n')
        f.write('[includes]\n')
        f.write('gcc_toolchain_base = %s\n' % gcc_root)
        f.write(getIncDirs(gxx_loc))
    finally:
        f.close()

def main():
    epilog = "By default llvm and gcc binaries are searched in the PATH."
    opt_parser = optparse.OptionParser(epilog=epilog)
    opt_parser.add_option("-l", "--llvm-root", dest="llvm_root",
                          help="use DIR as a root path to the llvm/clang installation folder",
                          metavar="DIR")
    opt_parser.add_option("-g", "--gcc-root", dest="gcc_root",
                          help="use DIR as a root path to the gcc installation folder",
                          metavar="DIR")

    (options, args) = opt_parser.parse_args()

    if len(args) != 0:
        opt_parser.error("incorrect number of arguments")

    cfg_path = _get_cfg_path()
    _write_config(cfg_path, options.llvm_root, options.gcc_root)

if __name__ == "__main__":
    main()
